﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Framework.Common.ConsistentHash
{
    /// <summary>
    /// Create the node list in the circle
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public abstract class NodeList<T>
    {
        internal int Replicate = 100;	//helps to add closure to the nodes in the ring
        internal uint[] Keys = null;	//ordered keys for better performance, contain all hashed node keys
        public Ring<T> Circle = new Ring<T>();//collection of  nodes in a circle
        public List<T> Nodes = new List<T>();//list of actual nodes before virtually got replicated

        protected NodeList(IEnumerable<T> nodes, int replicate)
        {
            Replicate = replicate;
            Nodes = nodes.ToList();
            Initialize();
        }

        protected NodeList(IEnumerable<T> nodes)
        {
            Nodes = nodes.ToList();
            Initialize();
        }

        protected NodeList()
        {
        }

        private uint Hash(T node, int virtualIndex)
        {
            return HashFactory.Calculate(node + "-" + virtualIndex);
        }

        public void Add(T node)
        {
            for (int i = 0; i < Replicate; i++)
            {
                uint hash = Hash(node, i);
                Circle[hash] = node;
            }
            Keys = Circle.Keys.ToArray();
            Nodes.Add(node);
            LogHelper.DebugFormat("ADD--{0}", node);
        }

        public void Remove(T node)
        {
            for (int i = 0; i < Replicate; i++)
            {
                uint hash = Hash(node, i);
                Circle.Remove(hash);
            }
            Keys = Circle.Keys.ToArray();
            bool success = Nodes.Remove(node);
            LogHelper.DebugFormat("DEL--{0}:{1}", node, success);
        }

        public void Initialize()
        {
            lock (GetType())
            {
                for (int k = 0; k < Nodes.Count; k++)
                {
                    for (int i = 0; i < Replicate; i++)
                    {
                        uint hash = Hash(Nodes[k], i);
                        Circle[hash] = Nodes[k];
                    }
                }
                Keys = Circle.Keys.ToArray();
            }
        }

    }
}
